﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Infrastructure.Model.DI;
using Microsoft.Extensions.DependencyInjection;

namespace Infrastructure.Extensions
{
    public static class AppServiceExtensions
    {
        /// <summary>
        /// 自动注册带有AppServiceAttribute标记的服务
        /// </summary>
        public static void AddAppService(this IServiceCollection services, params string[] assemblyNames)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
            if (assemblyNames == null || assemblyNames.Length == 0)
                throw new ArgumentException("Assembly names cannot be null or empty", nameof(assemblyNames));

            foreach (var assemblyName in assemblyNames)
            {
                try
                {
                    var assembly = Assembly.Load(assemblyName);
                    RegisterServices(services, assembly);
                }
                catch (Exception ex)
                {
                    throw new InvalidOperationException($"Failed to load assembly: {assemblyName}", ex);
                }
            }
        }

        private static void RegisterServices(IServiceCollection services, Assembly assembly)
        {
            foreach (var type in assembly.GetExportedTypes())
            {
                var attribute = type.GetCustomAttribute<AppServiceAttribute>();
                if (attribute == null) continue;

                var serviceType = GetServiceType(type, attribute);
                AddServiceWithLifetime(services, serviceType, type, attribute.ServiceLifetime);
            }
        }

        private static Type GetServiceType(Type implementationType, AppServiceAttribute attribute)
        {
            if (attribute.ServiceType != null)
                return attribute.ServiceType;

            if (attribute.InterfaceServiceType)
                return implementationType.GetInterfaces().FirstOrDefault();

            return implementationType;
        }

        /// <summary>
        /// 根据指定的生命周期模式，将服务注册到依赖注入容器中
        /// </summary>
        /// <param name="services">服务集合（IServiceCollection）</param>
        /// <param name="serviceType">服务类型（接口或抽象类）</param>
        /// <param name="implementationType">实现类型（具体类）</param>
        /// <param name="lifetime">生命周期模式</param>
        private static void AddServiceWithLifetime(IServiceCollection services, Type serviceType, Type implementationType, LifeTime lifetime)
        {
            switch (lifetime)
            {
                case LifeTime.Singleton:
                    // Singleton（单例模式）：
                    // - 整个应用程序生命周期内只创建一个实例。
                    // - 所有请求共享同一个实例。
                    // - 适用于无状态的工具类服务（如日志记录器、配置服务等）。
                    // ⚠️ 注意：如果单例服务依赖了作用域服务，会导致作用域服务变成事实上的单例，可能引发问题。
                    services.AddSingleton(serviceType, implementationType);
                    break;

                case LifeTime.Scoped:
                    // Scoped（作用域模式）：
                    // - 每个 HTTP 请求范围内创建一个实例（即一次请求内复用同一个实例）。
                    // - 不同请求之间实例隔离。
                    // - 适用于需要保持请求级状态的服务（如数据库上下文、用户会话等）。
                    // 🌟 典型场景：ASP.NET Core 中 DbContext 默认使用 Scoped 生命周期。
                    services.AddScoped(serviceType, implementationType);
                    break;

                case LifeTime.Transient:
                default:
                    // Transient（瞬时模式）：
                    // - 每次从依赖注入容器请求时都创建一个新实例。
                    // - 适用于轻量级、无状态且创建成本低的服务。
                    // ⚠️ 注意：频繁创建可能导致性能问题，需谨慎用于高并发场景。
                    services.AddTransient(serviceType, implementationType);
                    break;
            }
        }
    }
}
